Model View Controller (MVC) Design Pattern in ASP.NET Core

ASP.NET Core वेब एप्लीकेशन में मॉडल व्यू कंट्रोलर (MVC)

ASP.NET Core वेब एप्लीकेशन में मॉडल-व्यू-कंट्रोलर (MVC) की कार्यप्रणाली को समझने के लिए एक सरल उदाहरण पर विचार करते हैं। मान लीजिए कि किसी यूज़र ने वेब एप्लीकेशन के इंडेक्स पेज के लिए रिक्वेस्ट भेजा। जब यह रिक्वेस्ट एप्लीकेशन के पास आता है, तो यह कंट्रोलर के पास प्रोसेस करने के लिए पहुँचता है। कंट्रोलर इस रिक्वेस्ट को हैंडल करता है और यह देखता है कि इस इंडेक्स पेज को किस प्रकार के डेटा की आवश्यकता है। डेटा को प्राप्त करने के लिए वह मॉडल से रिक्वेस्ट करता है। मॉडल डेटाबेस से संबंधित डेटा को निकाल कर कंट्रोलर के पास वापस भेज देता है। इस तरीके से हम देखते हैं कि कंट्रोलर और मॉडल के बीच में परस्पर संवाद होता है। जब कंट्रोलर को मॉडल के द्वारा डेटा प्राप्त हो जाता है, तब इसके बाद कंट्रोलर उस HTML टेंप्लेट को खोजता है, जिसकी ज़रूरत डेटा को प्रदर्शित करने के लिए होती है। जब संबंधित व्यू पेज प्राप्त हो जाता है, तो मॉडल के डेटा को कंट्रोलर व्यू पेज के पास भेज देता है। व्यू पेज के भीतर डेटा का उपयोग कर लिया जाता है। इसके बाद कंट्रोलर का एक्शन मेथड रिजल्ट को व्यू इंजन के पास भेज देता है। व्यू इंजन पेज की रेंडरिंग करता है और HTML पेज अंततोगत्वा क्लाइंट के पास भेज दिया जाता है।

MVC में रिक्वेस्ट प्रोसेसिंग

इस उदाहरण में हमने देखा कि किस प्रकार एक रिक्वेस्ट की प्रोसेसिंग कंट्रोलर के द्वारा की जाती है और डेटा के लिए किस प्रकार कंट्रोलर और मॉडल के बीच में कम्युनिकेशन होता है। साथ ही हमने यह भी देखा कि डेटा को प्रदर्शित करने के लिए किस प्रकार रेज़र व्यू का उपयोग किया जाता है और अंतिम रूप से व्यू इंजन का उपयोग किस प्रकार पेज को रेंडर करने के लिए किया जाता है।


विभिन्न फॉर्मेट्स में डेटा रेंडरिंग

ऐसा कोई आवश्यक नहीं है कि प्रत्येक मॉडल-व्यू-कंट्रोलर डिज़ाइन पैटर्न के भीतर HTML पेज को ही रेंडर किया जाए। ऐसा भी हो सकता है कि एप्लीकेशन के द्वारा डेटा को XML या JSON फॉर्मेट में या प्लेन टेक्स्ट के रूप में क्लाइंट के पास भेजा जाए। उदाहरण के लिए, मोबाइल फ़ोन के द्वारा रिक्वेस्ट करने पर आमतौर पर एक XML या JSON फॉर्मेट में डेटा को वापस भेजा जाता है, जबकि किसी ब्राउज़र के द्वारा रिक्वेस्ट करने पर HTML पेज को क्लाइंट के पास भेजा जाता है।

MVC के महत्वपूर्ण कंपोनेंट्स

मॉडल-व्यू-कंट्रोलर डिज़ाइन पैटर्न के अंतर्गत महत्वपूर्ण कॉम्पोनेंट होते हैं: मॉडल, व्यू और कंट्रोलर

  • मॉडल का उपयोग डेटा को एप्लीकेशन के भीतर प्रदर्शित करने के लिए किया जाता है। दूसरे शब्दों में, मॉडल का काम डेटा को सोर्स से प्राप्त करके प्रदर्शित करना होता है।
  • जबकि व्यू का काम एक टेंप्लेट प्रदान करना होता है। इस टेंप्लेट के भीतर डेटा को प्रदर्शित किया जाता है जो डेटा मॉडल के द्वारा प्रदान किया गया है।
  • कंट्रोलर का काम मॉडल और व्यू के बीच में एक मध्यस्थ की तरह होता है। यह उन सारी प्रक्रियाओं का नियंत्रण करता है जो डेटा को प्राप्त करने और प्रदर्शित करने के दौरान होती हैं।

साधारण तौर पर एप्लीकेशन के भीतर इन घटनाओं का क्रम वही होता है जो हमने पीछे देखा है: सबसे पहले कंट्रोलर एक रिक्वेस्ट को प्राप्त करता है। उस रिक्वेस्ट के आधार पर कंट्रोलर या तो डेटा के लिए मॉडल से रिक्वेस्ट करता है और मॉडल उसे डेटा प्रदान करता है। दूसरी संभावना यह है कि डेटा का अपडेट मॉडल के द्वारा किया जाता है। इसके बाद कंट्रोलर व्यू का सिलेक्शन करता है जिसके ऊपर डेटा को प्रदर्शित करना है। कंट्रोलर यूज़र इंटरफ़ेस को जनरेट करने के लिए व्यू का उपयोग करता है।

कंट्रोलर एक्शन मेथड्स

ध्यान देने वाली बात यह है कि रिक्वेस्ट के नेचर के आधार पर कंट्रोलर विभिन्न प्रकार के एक्शन को क्रियान्वित कर सकता है। कंट्रोलर के भीतर अलग-अलग प्रकार के क्रियाकलाप को संपादित करने के लिए अलग-अलग प्रकार के एक्शन मेथड होते हैं। जिस प्रकार का रिक्वेस्ट होता है, उसी के अनुसार कंट्रोलर के भीतर एक्शन मेथड का चयन होता है। एक्शन मेथड के भीतर संबंधित बिज़नेस लॉजिक लिखा गया होता है। जब एक एक्शन मेथड का चयन किया जाता है कंट्रोलर के द्वारा, तो उसी के आधार पर बिज़नेस लॉजिक को एग्जीक्यूट किया जाता है।


ई-कॉमर्स वेबसाइट में MVC का उदाहरण

अब हम मॉडल-व्यू-कंट्रोलर डिज़ाइन पैटर्न पर आधारित एक ई-कॉमर्स वेबसाइट एप्लीकेशन की बात करेंगे और समझेंगे कि कैसे किसी नए प्रोडक्ट को डेटाबेस में जोड़ने के लिए मॉडल-व्यू-कंट्रोलर का उपयोग किया जाता है।

  1. जब एक नए प्रोडक्ट को डेटाबेस में जोड़ना होता है, तो इससे संबंधित रिक्वेस्ट कंट्रोलर के पास आता है। कंट्रोलर के पास इस रिक्वेस्ट के साथ नए प्रोडक्ट का डेटा आता है।
  2. कंट्रोलर इस डेटा को मॉडल के पास भेज देता है। मॉडल के पास डेटाबेस में नया प्रोडक्ट को इंसर्ट करने से संबंधित बिज़नेस लॉजिक लिखा हुआ होता है। इस आधार पर मॉडल डेटाबेस में नए प्रोडक्ट को इंसर्ट कर देता है। इस तरीके से डेटाबेस टेबल अपडेट हो जाता है।
  3. तत्पश्चात, मॉडल इस कार्य के सफलता के बारे में कंट्रोलर को सूचित कर देता है और कंट्रोलर इस सूचना को या तो XML या JSON या HTML पेज पर रेंडर कर देता है। सूचना को XML या JSON के रूप में भेजा जाए, इसका निर्णय क्लाइंट के प्रकृति को ध्यान में रखकर किया जाता है।
  4. यदि क्लाइंट एक मोबाइल एप्लीकेशन हो, तो आम तौर पर XML या JSON के रूप में डेटा को रिटर्न किया जाता है। इसके विपरीत, यदि क्लाइंट एक वेब एप्लीकेशन ब्राउज़र हो, तो HTML पेज के रूप में डेटा को रेंडर किया जाता है।

इसके विपरीत, यदि किसी प्रोडक्ट के संबंध में जानकारी क्लाइंट के द्वारा मांगी जाती है, तो इस रिक्वेस्ट को प्रोसेस करने के लिए कंट्रोलर मॉडल के साथ कम्युनिकेशन करता है। मॉडल डेटाबेस से संबंधित सूचना को प्राप्त करके कंट्रोलर को रिटर्न कर देता है। इसके बाद कंट्रोलर इस सूचना या डेटा को प्रदर्शित करने के लिए संबंधित रेज़र टेंप्लेट का चयन करता है और रेज़र व्यू के ऊपर उस डेटा को प्रदर्शित कर दिया जाता है।


MVC डिज़ाइन पैटर्न की खूबियाँ

मॉडल-व्यू-कंट्रोलर डिज़ाइन पैटर्न की सबसे बड़ी खूबियाँ यह है कि इसमें मॉडल, व्यू और कंट्रोलर तीनों ही आपस में एक तरह से स्वतंत्र होते हैं। खासकर मॉडल और व्यू के बीच में पूरी स्वतंत्रता होती है, जिसके कारण एप्लीकेशन की टेस्टिंग करना सरल हो जाता है।

आमतौर पर यूज़र इंटरफ़ेस से संबंधित कोड की टेस्टिंग करना कठिन होता है, लेकिन मॉडल-व्यू-कंट्रोलर डिज़ाइन पैटर्न में मॉडल और व्यू के बीच में स्वतंत्रता होने के कारण टेस्टिंग सरल हो जाती है।

आमतौर पर मॉडल की टेस्टिंग की जाती है और इसके लिए यूज़र इंटरफ़ेस अर्थात रेज़र पर निर्भर नहीं रहना पड़ता है। मॉडल के भीतर ही एप्लीकेशन के बिज़नेस लॉजिक लिखी होती है और मॉडल की टेस्टिंग करना पर्याप्त होता है।

एक बार जब कंट्रोलर के द्वारा रेज़र व्यू का चयन कर लिया जाता है, तब उस रेज़र टेंपलेट के भीतर मॉडल का डेटा पास कर दिया जाता है और व्यू के ऊपर उस डेटा को HTML पेज के रूप में रेंडर कर दिया जाता है।

तो हम देखते हैं कि मुख्य बात यह है कि डेटा का वैलिडेशन मॉडल के ऊपर निर्भर करता है, न कि रेज़र व्यू के ऊपर। अतः, मॉडल की टेस्टिंग ही पर्याप्त होती है।


मॉडल और व्यू मॉडल में अंतर

कभी-कभी मॉडल शब्द के प्रति कन्फ्यूजन होता है क्योंकि जो डेटा व्यू के ऊपर प्रदर्शित किया जाता है, उस डेटा को व्यूमॉडल के नाम से जाना जाता है। आमतौर पर यह कार्य सेपरेशन ऑफ़ कंसर्न को ध्यान में रखकर किया जाता है। व्यूमॉडल का उपयोग व्यू पेज के ऊपर डेटा को प्रदर्शित करने के लिए किया जाता है, जबकि मॉडल शब्द का प्रयोग उस डेटा के लिए किया जाता है, जिसका सीधा संबंध डेटाबेस टेबल के साथ जुड़ा होता है। इसी मॉडल को आमतौर पर एंटीटी मॉडल कहते हैं, जिसका संबंध डेटाबेस टेबल से जुड़ा होता है।

किसी साधारण एप्लीकेशन के भीतर व्यूमॉडल बनाने की आवश्यकता नहीं पड़ती, लेकिन आमतौर पर किसी भी बड़े एप्लीकेशन के भीतर एप्लीकेशन की सुरक्षा के लिए ऐसा करना अति आवश्यक है। ऐसा नहीं करने पर ओवरपोस्टिंग की समस्या उत्पन्न हो सकती है।

ओवरपोस्टिंग और अंडरपोस्टिंग की समस्या से बचने के लिए एप्लीकेशन के भीतर डेटा ट्रांसफर ऑब्जेक्ट (DTO) और व्यूमॉडल का प्रयोग करना चाहिए।


मॉडल बाइंडिंग

अब हम इस लेख में बाइंडिंग मॉडल या मॉडल बाइंडिंग के संबंध में जानकारी एकत्र करेंगे। देखिए, जब एप्लीकेशन के पास कोई HTTP रिक्वेस्ट आता है, तो रूटिंग सिस्टम के द्वारा उस रिक्वेस्ट को संबंधित कंट्रोलर के पास भेज दिया जाता है। जब रिक्वेस्ट कंट्रोलर के पास आता है, तो उस कंट्रोलर के भीतर जो भी संबंधित एक्शन मेथड होता है, उसे एक्शन मेथड को उस रिक्वेस्ट को प्रोसेस करने की जिम्मेदारी सौंप दी जाती है। यदि एक्शन मेथड के पास कई सारे पैरामीटर होते हैं, तो उन पैरामीटर का बाइंडिंग आने वाले रिक्वेस्ट के डेटा के साथ किया जाता है। यह कार्य एप्लीकेशन के भीतर स्वतः ही होता है और इसके लिए डेवलपर को स्वयं कुछ नहीं करना पड़ता है। इस पूरी प्रक्रिया को मॉडल बाइंडिंग के नाम से जाना जाता है। मॉडल बाइंडिंग के अंतर्गत, आने वाले इनकमिंग डेटा की मैपिंग एक्शन मेथड के पैरामीटर के साथ की जाती है। यदि मैपिंग सफल होती है, तो यह माना जाता है कि मॉडल स्टेट सही है, अन्यथा मॉडल स्टेट दोषपूर्ण माना जाता है। वस्तुतः, कंट्रोलर क्लास, कंट्रोलर बेस क्लास से इनहेरिट किया जाता है। यह कंट्रोलर क्लास एक मॉडल स्टेट नाम का प्रॉपर्टी रखता है। इसी मॉडल स्टेट प्रॉपर्टी की वैल्यू की सेटिंग मॉडल बाइंडिंग की प्रक्रिया में होती है। यदि मॉडल बाइंडिंग सफल होता है, तो ModelState की वैल्यू True होती है, अन्यथा यह False होती है।

डेवलपर के द्वारा एक्शन मेथड के पैरामीटर को एक्सप्लीसिटली भी सूचित किया जा सकता है कि किस HTTP रिक्वेस्ट के किस डेटा के साथ उसका संबंध है। उदाहरण के लिए, HTTP रिक्वेस्ट के हेडर या बॉडी में से किस डेटा के साथ किसी पैरामीटर की बाइंडिंग होगी, इसके लिए पैरामीटर को एक एट्रिब्यूट प्रदान किया जा सकता है। इस बात को हम निम्नलिखित उदाहरण से समझ सकते हैं, जिसमें स्पष्ट दिखाया गया है कि आने वाले डेटा की बाइंडिंग एक्शन मेथड के किस डेटा के साथ हो रही है।

HTTP रिक्वेस्ट पैरामीटर बाइंडिंग का उदाहरण

निम्नलिखित उदाहरण से समझ सकते हैं, जिसमें स्पष्ट दिखाया गया है कि आने वाले डेटा की बाइंडिंग एक्शन मेथड के किस डेटा के साथ हो रही है:


[HttpPost]
public IActionResult CreateProduct(
    [FromRoute] int categoryId,
    [FromQuery] string productName,
    [FromBody] ProductCreateModel productData)
{
    // इस एक्शन मेथड में:
    // 1. categoryId रूट (URL) से बाइंड होगा।
    //    उदाहरण: /Products/Create/5 (जहां 5 categoryId है)
    // 2. productName क्वेरी स्ट्रिंग से बाइंड होगा।
    //    उदाहरण: /Products/Create/5?productName=Laptop
    // 3. productData HTTP रिक्वेस्ट की बॉडी (आमतौर पर JSON) से बाइंड होगी।
    //    उदाहरण: { "Name": "New Product", "Price": 1200.00 }
    // मॉडल बाइंडिंग सफल होने पर, productData ऑब्जेक्ट में रिक्वेस्ट बॉडी का डेटा होगा।
    if (ModelState.IsValid)
    {
        // यहाँ बिजनेस लॉजिक लिखा जाएगा
        // जैसे, productData को डेटाबेस में सहेजना
        return Ok("Product created successfully!");
    }
    else
    {
        // मॉडल बाइंडिंग विफल होने पर, त्रुटियों को वापस करें
        return BadRequest(ModelState);
    }
}
// ProductCreateModel क्लास
public class ProductCreateModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
}
        

इस उदाहरण में, हमने [FromRoute], [FromQuery], और [FromBody] जैसे एट्रिब्यूट का उपयोग किया है। ये एट्रिब्यूट ASP.NET Core को स्पष्ट रूप से बताते हैं कि एक्शन मेथड के पैरामीटर को HTTP रिक्वेस्ट के किस भाग (जैसे, URL का रूट, क्वेरी स्ट्रिंग, या रिक्वेस्ट बॉडी) से डेटा प्राप्त करना है। यह मॉडल बाइंडिंग प्रक्रिया को नियंत्रित करने और सुनिश्चित करने में मदद करता है कि सही डेटा सही पैरामीटर में मैप किया गया है।


डेटा वैलिडेशन के लिए Data Annotations का प्रयोग

साथ ही, डेटा वैलिडेशन के लिए मॉडल या व्यू मॉडल क्लास में Data Annotations का प्रयोग कर सकते हैं। यह ASP.NET Core MVC में इनपुट डेटा को मान्य करने का एक बहुत ही शक्तिशाली और सुविधाजनक तरीका है।

Data Annotations विशेष एट्रिब्यूट होते हैं जिन्हें आप अपनी मॉडल या व्यू मॉडल क्लास की प्रॉपर्टीज़ पर लागू करते हैं। ये एट्रिब्यूट परिभाषित करते हैं कि डेटा को किस प्रकार मान्य किया जाना चाहिए। जब मॉडल बाइंडिंग होती है और डेटा कंट्रोलर के एक्शन मेथड तक पहुँचता है, तो MVC फ्रेमवर्क स्वचालित रूप से इन Data Annotations का उपयोग करके डेटा को मान्य करता है।

यहाँ एक उदाहरण दिया गया है:


using System.ComponentModel.DataAnnotations;
public class ProductCreateModel
{
    [Required(ErrorMessage = "उत्पाद का नाम आवश्यक है।")]
    [StringLength(100, MinimumLength = 3, ErrorMessage = "उत्पाद का नाम 3 से 100 वर्णों के बीच होना चाहिए।")]
    public string Name { get; set; }
    [Required(ErrorMessage = "मूल्य आवश्यक है।")]
    [Range(0.01, 10000.00, ErrorMessage = "मूल्य 0.01 से 10000.00 के बीच होना चाहिए।")]
    public decimal Price { get; set; }
    [EmailAddress(ErrorMessage = "कृपया एक वैध ईमेल पता दर्ज करें।")]
    public string ContactEmail { get; set; }
    [Phone(ErrorMessage = "कृपया एक वैध फ़ोन नंबर दर्ज करें।")]
    public string PhoneNumber { get; set; }
    [DataType(DataType.Date)]
    [Display(Name = "उत्पाद की समाप्ति तिथि")]
    public DateTime ExpiryDate { get; set; }
}
        

इस उदाहरण में:

  • [Required]: यह सुनिश्चित करता है कि Name और Price फ़ील्ड खाली नहीं छोड़े जा सकते। यदि उपयोगकर्ता इन फ़ील्ड को खाली छोड़ता है, तो निर्दिष्ट ErrorMessage प्रदर्शित होगा।
  • [StringLength]: यह Name फ़ील्ड की न्यूनतम और अधिकतम लंबाई को परिभाषित करता है।
  • [Range]: यह Price फ़ील्ड के लिए एक संख्यात्मक सीमा निर्धारित करता है।
  • [EmailAddress]: यह ContactEmail फ़ील्ड के इनपुट को एक वैध ईमेल प्रारूप के लिए मान्य करता है।
  • [Phone]: यह PhoneNumber फ़ील्ड के इनपुट को एक वैध फ़ोन नंबर प्रारूप के लिए मान्य करता है।
  • [DataType]: यह केवल UI हिंट के लिए है, डेटा प्रकार को इंगित करता है, जैसे कि Date।
  • [Display]: यह UI में फ़ील्ड के लिए एक अधिक उपयोगकर्ता-अनुकूल नाम प्रदान करता है।

वैलिडेशन कैसे काम करता है?

जब आप इस ProductCreateModel का उपयोग किसी एक्शन मेथड में करते हैं, तो मॉडल बाइंडिंग के बाद आप ModelState.IsValid प्रॉपर्टी की जाँच कर सकते हैं:


[HttpPost]
public IActionResult CreateProduct([FromBody] ProductCreateModel productData)
{
    if (ModelState.IsValid)
    {
        // डेटा वैध है, आगे की प्रोसेसिंग करें
        // जैसे, productData को डेटाबेस में सहेजें
        return Ok("उत्पाद सफलतापूर्वक बनाया गया!");
    }
    else
    {
        // डेटा अमान्य है, त्रुटियों को क्लाइंट को वापस करें
        return BadRequest(ModelState); // यह अमान्यता की जानकारी (त्रुटि संदेशों सहित) लौटाएगा
    }
}
        

यदि ModelState.IsValid false है, तो इसका मतलब है कि Data Annotations द्वारा परिभाषित किसी भी वैलिडेशन नियम का उल्लंघन किया गया है। ModelState ऑब्जेक्ट में इन सभी वैलिडेशन त्रुटियों का विवरण होता है, जिसे आप उपयोगकर्ता को वापस भेज सकते हैं।

Data Annotations का उपयोग करके, आप अपने डेटा वैलिडेशन लॉजिक को मॉडल/व्यू मॉडल क्लासेस में केंद्रीकृत कर सकते हैं, जिससे कोड साफ, पढ़ने योग्य और बनाए रखने में आसान हो जाता है। यह क्लाइंट-साइड वैलिडेशन के साथ भी आसानी से एकीकृत हो सकता है, जिससे उपयोगकर्ता को सर्वर पर अनुरोध भेजने से पहले ही प्रतिक्रिया मिल जाती है।

टिप्पणियाँ

इस ब्लॉग से लोकप्रिय पोस्ट

Differences between in-process and out-of-process hosting models

Web Fundamental Concepts in Hindi for Beginners - FAQs with their Answers Part-1

Introduction to ASP.NET Core and Web Frameworks